package com.yunke.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunke.entity.YunkeFile;
import com.yunke.mapper.YunkeFileMapper;
import com.yunke.service.YunkeFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 文件管理服务实现类
 * 
 * @author yunke
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class YunkeFileServiceImpl extends ServiceImpl<YunkeFileMapper, YunkeFile> implements YunkeFileService {

    private final YunkeFileMapper yunkeFileMapper;

    // 文件上传根目录
    private static final String UPLOAD_ROOT_PATH = "uploads";
    
    // 支持的文件类型
    private static final String[] IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"};
    private static final String[] VIDEO_EXTENSIONS = {".mp4", ".avi", ".mov", ".wmv", ".flv", ".mkv"};
    private static final String[] AUDIO_EXTENSIONS = {".mp3", ".wav", ".flac", ".aac", ".ogg"};
    private static final String[] DOCUMENT_EXTENSIONS = {".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt"};

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeFile uploadFile(MultipartFile file, String fileCategory, String businessType, Long businessId) {
        try {
            if (file.isEmpty()) {
                throw new RuntimeException("文件不能为空");
            }

            // 获取原始文件名和扩展名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = getFileExtension(originalFilename);
            
            // 计算文件MD5
            String fileMd5 = DigestUtils.md5DigestAsHex(file.getBytes());
            
            // 检查文件是否已存在
            YunkeFile existingFile = yunkeFileMapper.selectByMd5(fileMd5);
            if (existingFile != null) {
                // 如果文件已存在，直接返回现有文件信息
                return existingFile;
            }

            // 生成新文件名
            String newFileName = UUID.randomUUID().toString() + fileExtension;
            
            // 构建文件路径（按日期分目录）
            String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            String relativePath = UPLOAD_ROOT_PATH + "/" + datePath + "/" + newFileName;
            
            // 创建目录
            Path uploadPath = Paths.get(relativePath).getParent();
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }
            
            // 保存文件到磁盘
            Path targetPath = Paths.get(relativePath);
            file.transferTo(targetPath.toFile());

            // 创建文件记录
            YunkeFile yunkeFile = new YunkeFile();
            yunkeFile.setFileName(newFileName);
            yunkeFile.setOriginalName(originalFilename);
            yunkeFile.setFileExt(fileExtension);
            yunkeFile.setFileType(getFileType(fileExtension));
            yunkeFile.setFileSize(file.getSize());
            yunkeFile.setFilePath(relativePath);
            yunkeFile.setFileUrl(getFileUrl(relativePath));
            yunkeFile.setFileMd5(fileMd5);
            yunkeFile.setStorageType(1); // 本地存储
            yunkeFile.setFileCategory(fileCategory);
            yunkeFile.setBusinessType(businessType);
            yunkeFile.setBusinessId(businessId);
            yunkeFile.setDownloadCount(0);
            yunkeFile.setAccessCount(0);
            yunkeFile.setIsPublic(true);
            yunkeFile.setIsTemp(false);
            yunkeFile.setStatus(0);
            yunkeFile.setCreateTime(System.currentTimeMillis());
            yunkeFile.setUpdateTime(System.currentTimeMillis());

            // TODO: 从当前登录用户获取userId
            yunkeFile.setUploadUserId(1L);
            yunkeFile.setUploadUserName("系统用户");

            this.save(yunkeFile);
            return yunkeFile;
            
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<YunkeFile> uploadFiles(MultipartFile[] files, String fileCategory, String businessType, Long businessId) {
        List<YunkeFile> uploadedFiles = new ArrayList<>();
        for (MultipartFile file : files) {
            YunkeFile yunkeFile = uploadFile(file, fileCategory, businessType, businessId);
            uploadedFiles.add(yunkeFile);
        }
        return uploadedFiles;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFile(Long id, Long userId) {
        try {
            YunkeFile file = this.getById(id);
            if (file == null || file.getStatus() == 1) {
                throw new RuntimeException("文件不存在");
            }

            // 检查权限（如果传入了userId）
            if (userId != null && !file.getUploadUserId().equals(userId)) {
                throw new RuntimeException("无权限删除此文件");
            }

            // 删除物理文件
            deletePhysicalFile(file.getFilePath());

            // 标记为删除
            file.setStatus(1);
            file.setUpdateTime(System.currentTimeMillis());
            return this.updateById(file);
            
        } catch (Exception e) {
            log.error("删除文件失败", e);
            throw new RuntimeException("删除文件失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFiles(List<Long> ids, Long userId) {
        for (Long id : ids) {
            if (!deleteFile(id, userId)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public IPage<YunkeFile> getFilePage(Integer current, Integer size, Integer fileType, 
                                       String fileCategory, String businessType, Long uploadUserId) {
        Page<YunkeFile> page = new Page<>(current, size);
        return yunkeFileMapper.selectFilePage(page, fileType, fileCategory, businessType, uploadUserId);
    }

    @Override
    public YunkeFile getFileById(Long id) {
        LambdaQueryWrapper<YunkeFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YunkeFile::getId, id)
               .eq(YunkeFile::getStatus, 0);
        return this.getOne(wrapper);
    }

    @Override
    public List<YunkeFile> getFilesByBusiness(String businessType, Long businessId) {
        return yunkeFileMapper.selectByBusiness(businessType, businessId);
    }

    @Override
    public List<YunkeFile> getFilesByUser(Long userId, Integer fileType, String fileCategory) {
        return yunkeFileMapper.selectByUser(userId, fileType, fileCategory);
    }

    @Override
    public String getDownloadUrl(Long id, Long userId) {
        YunkeFile file = this.getFileById(id);
        if (file == null) {
            return null;
        }

        // 检查权限
        if (!checkFilePermission(id, userId)) {
            return null;
        }

        return file.getFileUrl();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean increaseDownloadCount(Long id) {
        return yunkeFileMapper.incrementDownloadCount(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean increaseAccessCount(Long id) {
        return yunkeFileMapper.incrementAccessCount(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cleanTempFiles() {
        try {
            List<YunkeFile> tempFiles = yunkeFileMapper.selectTempFiles();
            for (YunkeFile file : tempFiles) {
                deletePhysicalFile(file.getFilePath());
                this.removeById(file.getId());
            }
            return true;
        } catch (Exception e) {
            log.error("清理临时文件失败", e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cleanExpiredFiles() {
        try {
            List<YunkeFile> expiredFiles = yunkeFileMapper.selectExpiredFiles();
            for (YunkeFile file : expiredFiles) {
                deletePhysicalFile(file.getFilePath());
                file.setStatus(1);
                file.setUpdateTime(System.currentTimeMillis());
                this.updateById(file);
            }
            return true;
        } catch (Exception e) {
            log.error("清理过期文件失败", e);
            return false;
        }
    }

    @Override
    public boolean checkFilePermission(Long fileId, Long userId) {
        YunkeFile file = this.getFileById(fileId);
        if (file == null) {
            return false;
        }

        // 公开文件或者是文件所有者
        return file.getIsPublic() || file.getUploadUserId().equals(userId);
    }

    @Override
    public boolean generateThumbnail(Long fileId) {
        // TODO: 实现缩略图生成逻辑
        return true;
    }

    @Override
    public long getTotalSize(Long userId, Integer fileType, String fileCategory) {
        return yunkeFileMapper.getTotalSize(userId, fileType, fileCategory);
    }

    @Override
    public long countFiles(Long userId, Integer fileType, String fileCategory) {
        return yunkeFileMapper.countFiles(userId, fileType, fileCategory);
    }

    @Override
    public List<String> getAllCategories() {
        return yunkeFileMapper.selectAllCategories();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean moveCategory(Long id, String newCategory, Long userId) {
        return yunkeFileMapper.updateFileCategory(id, newCategory, userId) > 0;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (!StringUtils.hasText(fileName)) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf(".");
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex) : "";
    }

    /**
     * 根据扩展名判断文件类型
     */
    private Integer getFileType(String extension) {
        if (!StringUtils.hasText(extension)) {
            return 5; // 其他
        }
        
        String ext = extension.toLowerCase();
        
        for (String imageExt : IMAGE_EXTENSIONS) {
            if (imageExt.equals(ext)) {
                return 1; // 图片
            }
        }
        
        for (String videoExt : VIDEO_EXTENSIONS) {
            if (videoExt.equals(ext)) {
                return 2; // 视频
            }
        }
        
        for (String audioExt : AUDIO_EXTENSIONS) {
            if (audioExt.equals(ext)) {
                return 3; // 音频
            }
        }
        
        for (String docExt : DOCUMENT_EXTENSIONS) {
            if (docExt.equals(ext)) {
                return 4; // 文档
            }
        }
        
        return 5; // 其他
    }

    /**
     * 生成文件访问URL
     */
    private String getFileUrl(String filePath) {
        // TODO: 根据配置生成正确的URL
        return "/files/" + filePath;
    }

    /**
     * 删除物理文件
     */
    private void deletePhysicalFile(String filePath) {
        try {
            Path path = Paths.get(filePath);
            if (Files.exists(path)) {
                Files.delete(path);
            }
        } catch (IOException e) {
            log.warn("删除物理文件失败: {}", filePath, e);
        }
    }
} 